using System;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Security;
using System.Text;
using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;

namespace Microsoft.Win32
{
	internal static partial class NativeMethods
	{
		internal enum ADLT
		{
			RECENT,
			FREQUENT
		}

		internal enum Facility
		{
			Control = 10,
			Dispatch = 2,
			Ese = 0xe5e,
			Itf = 4,
			Null = 0,
			Rpc = 1,
			Storage = 3,
			Win32 = 7,
			Windows = 8
		}

		internal enum FDAP : uint
		{
			BOTTOM = 0,
			TOP = 1
		}

		internal enum FDEOR
		{
			DEFAULT,
			ACCEPT,
			REFUSE
		}

		internal enum FDESVR
		{
			DEFAULT,
			ACCEPT,
			REFUSE
		}

		[Flags]
		internal enum FOS : uint
		{
			ALLNONSTORAGEITEMS = 0x80,
			ALLOWMULTISELECT = 0x200,
			CREATEPROMPT = 0x2000,
			DEFAULTNOMINIMODE = 0x20000000,
			DONTADDTORECENT = 0x2000000,
			FILEMUSTEXIST = 0x1000,
			FORCEFILESYSTEM = 0x40,
			FORCEPREVIEWPANEON = 0x40000000,
			FORCESHOWHIDDEN = 0x10000000,
			HIDEMRUPLACES = 0x20000,
			HIDEPINNEDPLACES = 0x40000,
			NOCHANGEDIR = 8,
			NODEREFERENCELINKS = 0x100000,
			NOREADONLYRETURN = 0x8000,
			NOTESTFILECREATE = 0x10000,
			NOVALIDATE = 0x100,
			OVERWRITEPROMPT = 2,
			PATHMUSTEXIST = 0x800,
			PICKFOLDERS = 0x20,
			SHAREAWARE = 0x4000,
			STRICTFILETYPES = 4
		}

		[Flags]
		internal enum GPS
		{
			BESTEFFORT = 0x40,
			DEFAULT = 0,
			DELAYCREATION = 0x20,
			FASTPROPERTIESONLY = 8,
			HANDLERPROPERTIESONLY = 1,
			MASK_VALID = 0xff,
			NO_OPLOCK = 0x80,
			OPENSLOWITEM = 0x10,
			READWRITE = 2,
			TEMPORARY = 4
		}

		internal enum KDC
		{
			FREQUENT = 1,
			RECENT = 2
		}

		[Flags]
		internal enum SFGAO : uint
		{
			BROWSABLE = 0x8000000,
			CANCOPY = 1,
			CANDELETE = 0x20,
			CANLINK = 4,
			CANMONIKER = 0x400000,
			CANMOVE = 2,
			CANRENAME = 0x10,
			CAPABILITYMASK = 0x177,
			COMPRESSED = 0x4000000,
			CONTENTSMASK = 0x80000000,
			DISPLAYATTRMASK = 0xfc000,
			DROPTARGET = 0x100,
			ENCRYPTED = 0x2000,
			FILESYSANCESTOR = 0x10000000,
			FILESYSTEM = 0x40000000,
			FOLDER = 0x20000000,
			GHOSTED = 0x8000,
			HASPROPSHEET = 0x40,
			HASSTORAGE = 0x400000,
			HASSUBFOLDER = 0x80000000,
			HIDDEN = 0x80000,
			ISSLOW = 0x4000,
			LINK = 0x10000,
			NEWCONTENT = 0x200000,
			NONENUMERATED = 0x100000,
			PKEYSFGAOMASK = 0x81044000,
			READONLY = 0x40000,
			REMOVABLE = 0x2000000,
			SHARE = 0x20000,
			STORAGE = 8,
			STORAGEANCESTOR = 0x800000,
			STORAGECAPMASK = 0x70c50008,
			STREAM = 0x400000,
			SYSTEM = 0x00001000,
			VALIDATE = 0x1000000
		}

		[Flags]
		internal enum SHCONTF
		{
			CHECKING_FOR_CHILDREN = 0x10,
			ENABLE_ASYNC = 0x8000,
			FASTITEMS = 0x2000,
			FLATLIST = 0x4000,
			FOLDERS = 0x20,
			INCLUDEHIDDEN = 0x80,
			INIT_ON_FIRST_NEXT = 0x100,
			NAVIGATION_ENUM = 0x1000,
			NETPRINTERSRCH = 0x200,
			NONFOLDERS = 0x40,
			SHAREABLE = 0x400,
			STORAGE = 0x800
		}

		[Flags]
		internal enum SHGDN
		{
			SHGDN_FORADDRESSBAR = 0x4000,
			SHGDN_FOREDITING = 0x1000,
			SHGDN_FORPARSING = 0x8000,
			SHGDN_INFOLDER = 1,
			SHGDN_NORMAL = 0
		}

		internal enum SIATTRIBFLAGS
		{
			AND = 1,
			APPCOMPAT = 3,
			OR = 2
		}

		[Flags]
		internal enum SICHINT : uint
		{
			ALLFIELDS = 0x80000000,
			CANONICAL = 0x10000000,
			DISPLAY = 0,
			TEST_FILESYSPATH_IF_NOT_EQUAL = 0x20000000
		}

		internal enum SIGDN : uint
		{
			DESKTOPABSOLUTEEDITING = 0x8004c000,
			DESKTOPABSOLUTEPARSING = 0x80028000,
			FILESYSPATH = 0x80058000,
			NORMALDISPLAY = 0,
			PARENTRELATIVE = 0x80080001,
			PARENTRELATIVEEDITING = 0x80031001,
			PARENTRELATIVEFORADDRESSBAR = 0x8007c001,
			PARENTRELATIVEFORUI = 0x80094001,
			PARENTRELATIVEPARSING = 0x80018001,
			URL = 0x80068000,
		}

		[Flags]
		internal enum SLGP
		{
			RAWPATH = 4,
			SHORTPATH = 1,
			UNCPRIORITY = 2,
			RELATIVEPRIORITY = 8
		}

		[Flags]
		internal enum STPF
		{
			NONE = 0,
			USEAPPPEEKALWAYS = 4,
			USEAPPPEEKWHENACTIVE = 8,
			USEAPPTHUMBNAILALWAYS = 1,
			USEAPPTHUMBNAILWHENACTIVE = 2
		}

		[Flags]
		internal enum TBPF
		{
			ERROR = 4,
			INDETERMINATE = 1,
			NOPROGRESS = 0,
			NORMAL = 2,
			PAUSED = 8
		}

		[Flags]
		internal enum THB : uint
		{
			BITMAP = 1,
			FLAGS = 8,
			ICON = 2,
			TOOLTIP = 4
		}

		[Flags]
		internal enum THBF : uint
		{
			DISABLED = 1,
			DISMISSONCLICK = 2,
			ENABLED = 0,
			HIDDEN = 8,
			NOBACKGROUND = 4,
			NONINTERACTIVE = 0x10
		}

		// Used to remove items from the automatic destination lists created when apps or the system call SHAddToRecentDocs to report usage of a document.
		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[ComImport, Guid("12337d35-94c6-48a0-bce7-6a9c69d4d600"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
		internal interface IApplicationDestinations
		{
			// Set the App User Model ID for the application removing destinations from its list.  If an AppID is not provided
			// via this method, the system will use a heuristically determined ID.  This method must be called before
			// RemoveDestination or RemoveAllDestinations.
			void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID);

			// Remove an IShellItem or an IShellLink from the automatic destination list
			void RemoveDestination([MarshalAs(UnmanagedType.IUnknown)] object punk);

			// Clear the frequent and recent destination lists for this application.
			void RemoveAllDestinations();
		}

		/// <summary>
		/// Allows an application to retrieve the most recent and frequent documents opened in that app, as reported via SHAddToRecentDocs
		/// </summary>
		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("3c594f9f-9f30-47a1-979a-c9e83d3d0a06")]
		internal interface IApplicationDocumentLists
		{
			/// <summary>
			/// Set the App User Model ID for the application retrieving this list.  If an AppID is not provided via this method,
			/// the system will use a heuristically determined ID.  This method must be called before GetList.
			/// </summary>
			/// <param name="pszAppID">App Id.</param>
			void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID);

			/// <summary>
			/// Retrieve an IEnumObjects or IObjectArray for IShellItems and/or IShellLinks.
			/// Items may appear in both the frequent and recent lists.
			/// </summary>
			/// <param name="listtype">Which of the known list types to retrieve</param>
			/// <param name="cItemsDesired">The number of items desired.</param>
			/// <param name="riid">The interface Id that the return value should be queried for.</param>
			/// <returns>A COM object based on the IID passed for the riid parameter.</returns>
			[return: MarshalAs(UnmanagedType.IUnknown)]
			object GetList(ADLT listtype, uint cItemsDesired, [In] ref Guid riid);
		}

		// Custom Destination List
		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("6332debf-87b5-4670-90c0-5e57b408a49e")]
		internal interface ICustomDestinationList
		{
			void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID);

			// Retrieve IObjectArray of IShellItems or IShellLinks that represent removed destinations
			[return: MarshalAs(UnmanagedType.Interface)]
			object BeginList(out uint pcMaxSlots, [In] ref Guid riid);

			// PreserveSig because this will return custom errors when attempting to add unregistered ShellItems.
			// Can't readily detect that case without just trying to append it.
			[PreserveSig]
			HRESULT AppendCategory([MarshalAs(UnmanagedType.LPWStr)] string pszCategory, IObjectArray poa);

			void AppendKnownCategory(KDC category);

			[PreserveSig]
			HRESULT AddUserTasks(IObjectArray poa);

			void CommitList();

			// Retrieve IObjectCollection of IShellItems
			[return: MarshalAs(UnmanagedType.Interface)]
			object GetRemovedDestinations([In] ref Guid riid);

			void DeleteList([MarshalAs(UnmanagedType.LPWStr)] string pszAppID);

			void AbortList();
		}

		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F2-0000-0000-C000-000000000046")]
		internal interface IEnumIDList
		{
			[PreserveSig()]
			HRESULT Next(uint celt, out IntPtr rgelt, out int pceltFetched);

			[PreserveSig()]
			HRESULT Skip(uint celt);

			void Reset();

			[return: MarshalAs(UnmanagedType.Interface)]
			IEnumIDList Clone();
		}

		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("42f85136-db7e-439c-85f1-e4075d135fc8")]
		internal interface IFileDialog : IModalWindow
		{
			[PreserveSig]
			new HRESULT Show(IntPtr parent);

			void SetFileTypes(uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] COMDLG_FILTERSPEC[] rgFilterSpec);

			void SetFileTypeIndex(uint iFileType);

			uint GetFileTypeIndex();

			uint Advise(IFileDialogEvents pfde);

			void Unadvise(uint dwCookie);

			void SetOptions(FOS fos);

			FOS GetOptions();

			void SetDefaultFolder(IShellItem psi);

			void SetFolder(IShellItem psi);

			IShellItem GetFolder();

			IShellItem GetCurrentSelection();

			void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName);

			[return: MarshalAs(UnmanagedType.LPWStr)]
			string GetFileName();

			void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle);

			void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText);

			void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel);

			IShellItem GetResult();

			void AddPlace(IShellItem psi, FDAP alignment);

			void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);

			void Close([MarshalAs(UnmanagedType.Error)] int hr);

			void SetClientGuid([In] ref Guid guid);

			void ClearClientData();

			void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter);
		}

		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("973510DB-7D7F-452B-8975-74A85828D354")]
		internal interface IFileDialogEvents
		{
			[PreserveSig]
			HRESULT OnFileOk(IFileDialog pfd);

			[PreserveSig]
			HRESULT OnFolderChanging(IFileDialog pfd, IShellItem psiFolder);

			[PreserveSig]
			HRESULT OnFolderChange(IFileDialog pfd);

			[PreserveSig]
			HRESULT OnSelectionChange(IFileDialog pfd);

			[PreserveSig]
			HRESULT OnShareViolation(IFileDialog pfd, IShellItem psi, out FDESVR pResponse);

			[PreserveSig]
			HRESULT OnTypeChange(IFileDialog pfd);

			[PreserveSig]
			HRESULT OnOverwrite(IFileDialog pfd, IShellItem psi, out FDEOR pResponse);
		}

		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("d57c7288-d4ad-4768-be02-9d969532d960")]
		internal interface IFileOpenDialog : IFileDialog
		{
			[PreserveSig]
			new HRESULT Show(IntPtr parent);

			new void SetFileTypes(uint cFileTypes, [In] COMDLG_FILTERSPEC[] rgFilterSpec);

			new void SetFileTypeIndex(uint iFileType);

			new uint GetFileTypeIndex();

			new uint Advise(IFileDialogEvents pfde);

			new void Unadvise(uint dwCookie);

			new void SetOptions(FOS fos);

			new FOS GetOptions();

			new void SetDefaultFolder(IShellItem psi);

			new void SetFolder(IShellItem psi);

			new IShellItem GetFolder();

			new IShellItem GetCurrentSelection();

			new void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName);

			[return: MarshalAs(UnmanagedType.LPWStr)]
			new void GetFileName();

			new void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle);

			new void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText);

			new void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel);

			new IShellItem GetResult();

			new void AddPlace(IShellItem psi, FDAP fdcp);

			new void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);

			new void Close([MarshalAs(UnmanagedType.Error)] int hr);

			new void SetClientGuid([In] ref Guid guid);

			new void ClearClientData();

			new void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter);

			IShellItemArray GetResults();

			IShellItemArray GetSelectedItems();
		}

		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("84bccd23-5fde-4cdb-aea4-af64b83d78ab")]
		internal interface IFileSaveDialog : IFileDialog
		{
			[PreserveSig]
			new HRESULT Show(IntPtr parent);

			new void SetFileTypes(uint cFileTypes, [In] COMDLG_FILTERSPEC[] rgFilterSpec);

			new void SetFileTypeIndex(uint iFileType);

			new uint GetFileTypeIndex();

			new uint Advise(IFileDialogEvents pfde);

			new void Unadvise(uint dwCookie);

			new void SetOptions(FOS fos);

			new FOS GetOptions();

			new void SetDefaultFolder(IShellItem psi);

			new void SetFolder(IShellItem psi);

			new IShellItem GetFolder();

			new IShellItem GetCurrentSelection();

			new void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName);

			[return: MarshalAs(UnmanagedType.LPWStr)]
			new void GetFileName();

			new void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle);

			new void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText);

			new void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel);

			new IShellItem GetResult();

			new void AddPlace(IShellItem psi, FDAP fdcp);

			new void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);

			new void Close([MarshalAs(UnmanagedType.Error)] int hr);

			new void SetClientGuid([In] ref Guid guid);

			new void ClearClientData();

			new void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter);

			void SetSaveAsItem(IShellItem psi);

			void SetProperties([In, MarshalAs(UnmanagedType.Interface)] object pStore);

			void SetCollectedProperties([In, MarshalAs(UnmanagedType.Interface)] object pList, [In] int fAppendDefault);

			[return: MarshalAs(UnmanagedType.Interface)]
			object GetProperties();

			void ApplyProperties(IShellItem psi, [MarshalAs(UnmanagedType.Interface)] object pStore, [In] ref IntPtr hwnd, [MarshalAs(UnmanagedType.Interface)] object pSink);
		}

		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("b4db1657-70d7-485e-8e3e-6fcb5a5c1802")]
		internal interface IModalWindow
		{
			[PreserveSig]
			HRESULT Show(IntPtr parent);
		}

		/// <summary>Unknown Object Array</summary>
		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("92CA9DCD-5622-4bba-A805-5E9F541BD8C9")]
		internal interface IObjectArray
		{
			uint GetCount();

			[return: MarshalAs(UnmanagedType.IUnknown)]
			object GetAt([In] uint uiIndex, [In] ref Guid riid);
		}

		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("92CA9DCD-5622-4bba-A805-5E9F541BD8C9")]
		internal interface IObjectCollection : IObjectArray
		{
			new uint GetCount();

			[return: MarshalAs(UnmanagedType.IUnknown)]
			new object GetAt([In] uint uiIndex, [In] ref Guid riid);

			void AddObject([MarshalAs(UnmanagedType.IUnknown)] object punk);

			void AddFromArray(IObjectArray poaSource);

			void RemoveObjectAt(uint uiIndex);

			void Clear();
		}

		/// <summary>
		/// Provides access to the App User Model ID on objects supporting this value.
		/// </summary>
		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("36db0196-9665-46d1-9ba7-d3709eecf9ed")]
		internal interface IObjectWithAppUserModelId
		{
			void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID);

			[return: MarshalAs(UnmanagedType.LPWStr)]
			string GetAppID();
		};

		/// <summary>
		/// Provides access to the ProgID associated with an object
		/// </summary>
		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("71e806fb-8dee-46fc-bf8c-7748a8a1ae13")]
		internal interface IObjectWithProgId
		{
			void SetProgID([MarshalAs(UnmanagedType.LPWStr)] string pszProgID);

			[return: MarshalAs(UnmanagedType.LPWStr)]
			string GetProgID();
		};

		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99")]
		internal interface IPropertyStore
		{
			uint GetCount();

			PKEY GetAt(uint iProp);

			void GetValue([In] REFPROPERTYKEY pkey, [In, Out] PROPVARIANT pv);

			void SetValue([In] REFPROPERTYKEY pkey, PROPVARIANT pv);

			void Commit();
		}

		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214E6-0000-0000-C000-000000000046")]
		internal interface IShellFolder
		{
			void ParseDisplayName(
				IntPtr hwnd,
				IBindCtx pbc,
				[MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName,
				[In, Out] ref int pchEaten,
				out IntPtr ppidl,
				[In, Out] ref uint pdwAttributes);

			IEnumIDList EnumObjects(
				IntPtr hwnd,
				SHCONTF grfFlags);

			// returns an instance of a sub-folder which is specified by the IDList (pidl).
			// IShellFolder or derived interfaces
			[return: MarshalAs(UnmanagedType.Interface)]
			object BindToObject(
				IntPtr pidl,
				IBindCtx pbc,
				[In] ref Guid riid);

			// produces the same result as BindToObject()
			[return: MarshalAs(UnmanagedType.Interface)]
			object BindToStorage(IntPtr pidl, IBindCtx pbc, [In] ref Guid riid);

			// compares two IDLists and returns the result. The shell
			// explorer always passes 0 as lParam, which indicates 'sort by name'.
			// It should return 0 (as CODE of the scode), if two id indicates the
			// same object; negative value if pidl1 should be placed before pidl2;
			// positive value if pidl2 should be placed before pidl1.
			// use the macro ResultFromShort() to extract the result comparison
			// it deals with the casting and type conversion issues for you
			[PreserveSig]
			HRESULT CompareIDs(IntPtr lParam, IntPtr pidl1, IntPtr pidl2);

			// creates a view object of the folder itself. The view
			// object is a difference instance from the shell folder object.
			// 'hwndOwner' can be used  as the owner window of its dialog box or
			// menu during the lifetime of the view object.
			// This member function should always create a new
			// instance which has only one reference count. The explorer may create
			// more than one instances of view object from one shell folder object
			// and treat them as separate instances.
			// returns IShellView derived interface
			[return: MarshalAs(UnmanagedType.Interface)]
			object CreateViewObject(IntPtr hwndOwner, [In] ref Guid riid);

			// returns the attributes of specified objects in that
			// folder. 'cidl' and 'apidl' specifies objects. 'apidl' contains only
			// simple IDLists. The explorer initializes *prgfInOut with a set of
			// flags to be evaluated. The shell folder may optimize the operation
			// by not returning unspecified flags.
			void GetAttributesOf(
				uint cidl,
				IntPtr apidl,
				[In, Out] ref SFGAO rgfInOut);

			// creates a UI object to be used for specified objects.
			// The shell explorer passes either IID_IDataObject (for transfer operation)
			// or IID_IContextMenu (for context menu operation) as riid
			// and many other interfaces
			[return: MarshalAs(UnmanagedType.Interface)]
			object GetUIObjectOf(
				IntPtr hwndOwner,
				uint cidl,
				[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.SysInt, SizeParamIndex = 1)] IntPtr apidl,
				[In] ref Guid riid,
				[In, Out] ref uint rgfReserved);

			// returns the display name of the specified object.
			// If the ID contains the display name (in the locale character set),
			// it returns the offset to the name. Otherwise, it returns a pointer
			// to the display name string (UNICODE), which is allocated by the
			// task allocator, or fills in a buffer.
			// use the helper APIS StrRetToStr() or StrRetToBuf() to deal with the different
			// forms of the STRRET structure
			void GetDisplayNameOf(IntPtr pidl, SHGDN uFlags, out IntPtr pName);

			// sets the display name of the specified object.
			// If it changes the ID as well, it returns the new ID which is
			// alocated by the task allocator.
			void SetNameOf(IntPtr hwnd,
				IntPtr pidl,
				[MarshalAs(UnmanagedType.LPWStr)] string pszName,
				SHGDN uFlags,
				out IntPtr ppidlOut);
		}

		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[
			ComImport,
			InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
			Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe"),
		]
		internal interface IShellItem
		{
			[return: MarshalAs(UnmanagedType.Interface)]
			object BindToHandler(IBindCtx pbc, [In] ref Guid bhid, [In] ref Guid riid);

			IShellItem GetParent();

			[return: MarshalAs(UnmanagedType.LPWStr)]
			string GetDisplayName(SIGDN sigdnName);

			uint GetAttributes(SFGAO sfgaoMask);

			int Compare(IShellItem psi, SICHINT hint);
		}

		/// <summary>
		/// Shell Namespace helper 2
		/// </summary>
		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[
			ComImport,
			InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
			Guid("7e9fb0d3-919f-4307-ab2e-9b1860310c93"),
		]
		internal interface IShellItem2 : IShellItem
		{
			[return: MarshalAs(UnmanagedType.Interface)]
			new object BindToHandler(IBindCtx pbc, [In] ref Guid bhid, [In] ref Guid riid);

			new IShellItem GetParent();

			[return: MarshalAs(UnmanagedType.LPWStr)]
			new string GetDisplayName(SIGDN sigdnName);

			new SFGAO GetAttributes(SFGAO sfgaoMask);

			new int Compare(IShellItem psi, SICHINT hint);

			[return: MarshalAs(UnmanagedType.Interface)]
			object GetPropertyStore(
				GPS flags,
				[In] ref Guid riid);

			[return: MarshalAs(UnmanagedType.Interface)]
			object GetPropertyStoreWithCreateObject(
				GPS flags,
				[MarshalAs(UnmanagedType.IUnknown)] object punkCreateObject,   // factory for low-rights creation of type ICreateObject
				[In] ref Guid riid);

			[return: MarshalAs(UnmanagedType.Interface)]
			object GetPropertyStoreForKeys(
				IntPtr rgKeys,
				uint cKeys,
				GPS flags,
				[In] ref Guid riid);

			[return: MarshalAs(UnmanagedType.Interface)]
			object GetPropertyDescriptionList(
				IntPtr keyType,
				[In] ref Guid riid);

			// Ensures any cached information in this item is up to date, or returns __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) if the item does not exist.
			void Update(IBindCtx pbc);

			void GetProperty([In] REFPROPERTYKEY key, [In, Out] PROPVARIANT pv);

			Guid GetCLSID([In] REFPROPERTYKEY key);

			FILETIME GetFileTime([In] REFPROPERTYKEY key);

			int GetInt32([In] REFPROPERTYKEY key);

			[return: MarshalAs(UnmanagedType.LPWStr)]
			string GetString([In] REFPROPERTYKEY key);

			uint GetUInt32([In] REFPROPERTYKEY key);

			ulong GetUInt64([In] REFPROPERTYKEY key);

			[return: MarshalAs(UnmanagedType.Bool)]
			bool GetBool([In] REFPROPERTYKEY key);
		}

		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[
			ComImport,
			InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
			Guid("B63EA76D-1F85-456F-A19C-48159EFA858B"),
		]
		internal interface IShellItemArray
		{
			[return: MarshalAs(UnmanagedType.Interface)]
			object BindToHandler(IBindCtx pbc, [In] ref Guid rbhid, [In] ref Guid riid);

			[return: MarshalAs(UnmanagedType.Interface)]
			object GetPropertyStore(int flags, [In] ref Guid riid);

			[return: MarshalAs(UnmanagedType.Interface)]
			object GetPropertyDescriptionList([In] ref PKEY keyType, [In] ref Guid riid);

			uint GetAttributes(SIATTRIBFLAGS dwAttribFlags, uint sfgaoMask);

			uint GetCount();

			IShellItem GetItemAt(uint dwIndex);

			[return: MarshalAs(UnmanagedType.Interface)]
			object EnumItems();
		}

		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[
			ComImport,
			InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown),
			Guid("000214F9-0000-0000-C000-000000000046"),
		]
		internal interface IShellLinkW
		{
			void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, [In, Out] WIN32_FIND_DATA pfd, SLGP fFlags);

			IntPtr GetIDList();

			void SetIDList(IntPtr pidl);

			void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxName);

			void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);

			void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);

			void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);

			void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);

			void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);

			short GetHotKey();

			void SetHotKey(short wHotKey);

			uint GetShowCmd();

			void SetShowCmd(uint iShowCmd);

			void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon);

			void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);

			void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved);

			void Resolve(IntPtr hwnd, uint fFlags);

			void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
		}

		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[
			ComImport,
			InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
			Guid("56FDF342-FD6D-11d0-958A-006097C9A090"),
		]
		internal interface ITaskbarList
		{
			/// <summary>
			/// This function must be called first to validate use of other members.
			/// </summary>
			void HrInit();

			/// <summary>
			/// This function adds a tab for hwnd to the taskbar.
			/// </summary>
			/// <param name="hwnd">The HWND for which to add the tab.
			void AddTab(IntPtr hwnd);

			/// <summary>
			/// This function deletes a tab for hwnd from the taskbar.
			/// </summary>
			/// <param name="hwnd">The HWND for which the tab is to be deleted.
			void DeleteTab(IntPtr hwnd);

			/// <summary>
			/// This function activates the tab associated with hwnd on the taskbar.
			/// </summary>
			/// <param name="hwnd">The HWND for which the tab is to be activated.
			void ActivateTab(IntPtr hwnd);

			/// <summary>
			/// This function marks hwnd in the taskbar as the active tab.
			/// </summary>
			/// <param name="hwnd">The HWND to activate.
			void SetActiveAlt(IntPtr hwnd);
		}

		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[
			ComImport,
			InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
			Guid("602D4995-B13A-429b-A66E-1935E44F4317"),
		]
		internal interface ITaskbarList2 : ITaskbarList
		{
			new void HrInit();

			new void AddTab(IntPtr hwnd);

			new void DeleteTab(IntPtr hwnd);

			new void ActivateTab(IntPtr hwnd);

			new void SetActiveAlt(IntPtr hwnd);

			/// <summary>
			/// Marks a window as full-screen.
			/// </summary>
			/// <param name="hwnd">The handle of the window to be marked.
			/// <param name="fFullscreen">A Boolean value marking the desired full-screen status of the window.
			/// <remarks>
			/// Setting the value of fFullscreen to true, the Shell treats this window as a full-screen window, and the taskbar
			/// is moved to the bottom of the z-order when this window is active.  Setting the value of fFullscreen to false
			/// removes the full-screen marking, but <i>does not</i> cause the Shell to treat the window as though it were
			/// definitely not full-screen.  With a false fFullscreen value, the Shell depends on its automatic detection facility
			/// to specify how the window should be treated, possibly still flagging the window as full-screen.
			/// </remarks>
			void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen);
		}

		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		/// <remarks>
		/// Methods on this interface are marked as PreserveSig because the implementation inconsistently
		/// surfaces errors in Explorer.  Many of these methods are implemented by posting messages
		/// to the desktop window, but if explorer is not running or currently busy then we get back
		/// error codes that must be handled by the caller.
		/// </remarks>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[
			ComImport,
			InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
			Guid("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf"),
		]
		internal interface ITaskbarList3 : ITaskbarList2
		{
			new void HrInit();

			new void AddTab(IntPtr hwnd);

			new void DeleteTab(IntPtr hwnd);

			new void ActivateTab(IntPtr hwnd);

			new void SetActiveAlt(IntPtr hwnd);

			new void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen);

			[PreserveSig]
			HRESULT SetProgressValue(IntPtr hwnd, ulong ullCompleted, ulong ullTotal);

			[PreserveSig]
			HRESULT SetProgressState(IntPtr hwnd, TBPF tbpFlags);

			[PreserveSig]
			HRESULT RegisterTab(IntPtr hwndTab, IntPtr hwndMDI);

			[PreserveSig]
			HRESULT UnregisterTab(IntPtr hwndTab);

			[PreserveSig]
			HRESULT SetTabOrder(IntPtr hwndTab, IntPtr hwndInsertBefore);

			[PreserveSig]
			HRESULT SetTabActive(IntPtr hwndTab, IntPtr hwndMDI, uint dwReserved);

			[PreserveSig]
			HRESULT ThumbBarAddButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons);

			[PreserveSig]
			HRESULT ThumbBarUpdateButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons);

			[PreserveSig]
			HRESULT ThumbBarSetImageList(IntPtr hwnd, IntPtr himl);

			[PreserveSig]
			HRESULT SetOverlayIcon(IntPtr hwnd, IntPtr hIcon, [MarshalAs(UnmanagedType.LPWStr)] string pszDescription);

			[PreserveSig]
			HRESULT SetThumbnailTooltip(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] string pszTip);

			// Using RefRECT to making passing NULL possible.  Removes clipping from the HWND.
			[PreserveSig]
			HRESULT SetThumbnailClip(IntPtr hwnd, ref RECT prcClip);
		}

		/// <securitynote>
		/// Critical: Suppresses unmanaged code security.
		/// </securitynote>
		[SecurityCritical(SecurityCriticalScope.Everything), SuppressUnmanagedCodeSecurity]
		[
			ComImport,
			InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
			Guid("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf"),
		]
		internal interface ITaskbarList4 : ITaskbarList3
		{
			new void HrInit();

			new void AddTab(IntPtr hwnd);

			new void DeleteTab(IntPtr hwnd);

			new void ActivateTab(IntPtr hwnd);

			new void SetActiveAlt(IntPtr hwnd);

			new void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen);

			[PreserveSig]
			new HRESULT SetProgressValue(IntPtr hwnd, ulong ullCompleted, ulong ullTotal);

			[PreserveSig]
			new HRESULT SetProgressState(IntPtr hwnd, TBPF tbpFlags);

			[PreserveSig]
			new HRESULT RegisterTab(IntPtr hwndTab, IntPtr hwndMDI);

			[PreserveSig]
			new HRESULT UnregisterTab(IntPtr hwndTab);

			[PreserveSig]
			new HRESULT SetTabOrder(IntPtr hwndTab, IntPtr hwndInsertBefore);

			[PreserveSig]
			new HRESULT SetTabActive(IntPtr hwndTab, IntPtr hwndMDI, uint dwReserved);

			[PreserveSig]
			new HRESULT ThumbBarAddButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons);

			[PreserveSig]
			new HRESULT ThumbBarUpdateButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons);

			[PreserveSig]
			new HRESULT ThumbBarSetImageList(IntPtr hwnd, IntPtr himl);

			[PreserveSig]
			new HRESULT SetOverlayIcon(IntPtr hwnd, IntPtr hIcon, [MarshalAs(UnmanagedType.LPWStr)] string pszDescription);

			[PreserveSig]
			new HRESULT SetThumbnailTooltip(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] string pszTip);

			[PreserveSig]
			new HRESULT SetThumbnailClip(IntPtr hwnd, ref RECT prcClip);

			[PreserveSig]
			HRESULT SetTabProperties(IntPtr hwndTab, STPF stpFlags);
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
		internal struct COMDLG_FILTERSPEC
		{
			[MarshalAs(UnmanagedType.LPWStr)]
			public string pszName;

			[MarshalAs(UnmanagedType.LPWStr)]
			public string pszSpec;
		}

		[StructLayout(LayoutKind.Explicit)]
		internal struct HRESULT
		{
			// Fields
			[FieldOffset(0)]
			private readonly uint _value;

			public static readonly HRESULT COR_E_OBJECTDISPOSED;
			public static readonly HRESULT DESTS_E_NO_MATCHING_ASSOC_HANDLER;
			public static readonly HRESULT DISP_E_BADINDEX;
			public static readonly HRESULT DISP_E_BADPARAMCOUNT;
			public static readonly HRESULT DISP_E_EXCEPTION;
			public static readonly HRESULT DISP_E_MEMBERNOTFOUND;
			public static readonly HRESULT DISP_E_OVERFLOW;
			public static readonly HRESULT DISP_E_PARAMNOTOPTIONAL;
			public static readonly HRESULT DISP_E_TYPEMISMATCH;
			public static readonly HRESULT DISP_E_UNKNOWNNAME;
			public static readonly HRESULT E_ABORT;
			public static readonly HRESULT E_ACCESSDENIED;
			public static readonly HRESULT E_FAIL;
			public static readonly HRESULT E_INVALIDARG;
			public static readonly HRESULT E_NOINTERFACE;
			public static readonly HRESULT E_NOTIMPL;
			public static readonly HRESULT E_OUTOFMEMORY;
			public static readonly HRESULT E_POINTER;
			public static readonly HRESULT E_UNEXPECTED;
			public static readonly HRESULT S_FALSE;
			public static readonly HRESULT S_OK;
			public static readonly HRESULT SCRIPT_E_REPORTED;
			public static readonly HRESULT STG_E_INVALIDFUNCTION;
			public static readonly HRESULT WC_E_GREATERTHAN;
			public static readonly HRESULT WC_E_SYNTAX;

			// Methods
			static HRESULT()
			{
				S_OK = new HRESULT(0);
				S_FALSE = new HRESULT(1);
				E_NOTIMPL = new HRESULT(0x80004001);
				E_NOINTERFACE = new HRESULT(0x80004002);
				E_POINTER = new HRESULT(0x80004003);
				E_ABORT = new HRESULT(0x80004004);
				E_FAIL = new HRESULT(0x80004005);
				E_UNEXPECTED = new HRESULT(0x8000ffff);
				DISP_E_MEMBERNOTFOUND = new HRESULT(0x80020003);
				DISP_E_TYPEMISMATCH = new HRESULT(0x80020005);
				DISP_E_UNKNOWNNAME = new HRESULT(0x80020006);
				DISP_E_EXCEPTION = new HRESULT(0x80020009);
				DISP_E_OVERFLOW = new HRESULT(0x8002000a);
				DISP_E_BADINDEX = new HRESULT(0x8002000b);
				DISP_E_BADPARAMCOUNT = new HRESULT(0x8002000e);
				DISP_E_PARAMNOTOPTIONAL = new HRESULT(0x8002000f);
				SCRIPT_E_REPORTED = new HRESULT(0x80020101);
				STG_E_INVALIDFUNCTION = new HRESULT(0x80030001);
				DESTS_E_NO_MATCHING_ASSOC_HANDLER = new HRESULT(0x80040f03);
				E_ACCESSDENIED = new HRESULT(0x80070005);
				E_OUTOFMEMORY = new HRESULT(0x8007000e);
				E_INVALIDARG = new HRESULT(0x80070057);
				COR_E_OBJECTDISPOSED = new HRESULT(0x80131622);
				WC_E_GREATERTHAN = new HRESULT(0xc00cee23);
				WC_E_SYNTAX = new HRESULT(0xc00cee2d);
			}

			public HRESULT(uint i)
			{
				_value = i;
			}

			public override bool Equals(object obj)
			{
				try
				{
					return (((HRESULT)obj)._value == _value);
				}
				catch (InvalidCastException)
				{
					return false;
				}
			}

			public static int GetCode(int error) => (error & 0xffff);

			public Exception GetException() => GetException(null);

			[SecurityCritical, SecurityTreatAsSafe]
			public Exception GetException(string message)
			{
				if (!Failed)
				{
					return null;
				}
				Exception exceptionForHR = Marshal.GetExceptionForHR((int)_value, new IntPtr(-1));
				if (exceptionForHR.GetType() == typeof(COMException))
				{
					if (Facility == Facility.Win32)
					{
						if (string.IsNullOrEmpty(message))
						{
							return new Win32Exception(Code);
						}
						return new Win32Exception(Code, message);
					}
					return new COMException(message ?? exceptionForHR.Message, (int)_value);
				}
				if (!string.IsNullOrEmpty(message))
				{
					Type[] types = new Type[] { typeof(string) };
					ConstructorInfo constructor = exceptionForHR.GetType().GetConstructor(types);
					if (null != constructor)
					{
						object[] parameters = new object[] { message };
						exceptionForHR = constructor.Invoke(parameters) as Exception;
					}
				}
				return exceptionForHR;
			}

			public static Facility GetFacility(int errorCode) => (((Facility)(errorCode >> 0x10)) & ((Facility)0x1fff));

			public override int GetHashCode() => _value.GetHashCode();

			public static HRESULT Make(bool severe, Facility facility, int code) => new HRESULT((uint)(((severe ? -2147483648 : 0) | (((int)facility) << 0x10)) | code));

			public static bool operator ==(HRESULT hrLeft, HRESULT hrRight) => (hrLeft._value == hrRight._value);

			public static bool operator !=(HRESULT hrLeft, HRESULT hrRight) => !(hrLeft == hrRight);

			public void ThrowIfFailed()
			{
				ThrowIfFailed(null);
			}

			[SecurityCritical, SecurityTreatAsSafe]
			public void ThrowIfFailed(string message)
			{
				Exception exception = GetException(message);
				if (exception != null)
				{
					throw exception;
				}
			}

			public override string ToString()
			{
				foreach (FieldInfo info in typeof(HRESULT).GetFields(BindingFlags.Public | BindingFlags.Static))
				{
					if ((info.FieldType == typeof(HRESULT)) && (((HRESULT)info.GetValue(null)) == this))
					{
						return info.Name;
					}
				}
				if (Facility == Facility.Win32)
				{
					foreach (FieldInfo info2 in typeof(Win32Error).GetFields(BindingFlags.Public | BindingFlags.Static))
					{
						if ((info2.FieldType == typeof(Win32Error)) && (((HRESULT)((Win32Error)info2.GetValue(null))) == this))
						{
							return ("HRESULT_FROM_WIN32(" + info2.Name + ")");
						}
					}
				}
				object[] args = new object[] { _value };
				return string.Format(CultureInfo.InvariantCulture, "0x{0:X8}", args);
			}

			// Properties
			public int Code => GetCode((int)_value);

			public Facility Facility => GetFacility((int)_value);

			public bool Failed => (_value < 0);

			public bool Succeeded => (_value >= 0);
		}

		[StructLayout(LayoutKind.Sequential, Pack = 4)]
		internal struct PKEY
		{
			/// <summary>fmtid</summary>
			private readonly Guid _fmtid;

			/// <summary>pid</summary>
			private readonly uint _pid;

			private PKEY(Guid fmtid, uint pid)
			{
				_fmtid = fmtid;
				_pid = pid;
			}

			public Guid Key => _fmtid;

			/// <summary>PKEY_Title</summary>
			public static readonly PKEY Title = new PKEY(new Guid("F29F85E0-4FF9-1068-AB91-08002B27B3D9"), 2);

			/// <summary>PKEY_AppUserModel_ID</summary>
			public static readonly PKEY AppUserModel_ID = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 5);

			/// <summary>PKEY_AppUserModel_IsDestListSeparator</summary>
			public static readonly PKEY AppUserModel_IsDestListSeparator = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 6);

			/// <summary>PKEY_AppUserModel_RelaunchCommand</summary>
			public static readonly PKEY AppUserModel_RelaunchCommand = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 2);

			/// <summary>PKEY_AppUserModel_RelaunchDisplayNameResource</summary>
			public static readonly PKEY AppUserModel_RelaunchDisplayNameResource = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 4);

			/// <summary>PKEY_AppUserModel_RelaunchIconResource</summary>
			public static readonly PKEY AppUserModel_RelaunchIconResource = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 3);
		}

		[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)]
		internal struct THUMBBUTTON
		{
			/// <summary>
			/// WPARAM value for a THUMBBUTTON being clicked.
			/// </summary>
			public const int THBN_CLICKED = 0x1800;

			public THB dwMask;
			public uint iId;
			public uint iBitmap;
			public IntPtr hIcon;

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
			public string szTip;

			public THBF dwFlags;

			public static THUMBBUTTON Default = new THUMBBUTTON() { dwMask = THB.FLAGS, dwFlags = THBF.HIDDEN };
		}

		[StructLayout(LayoutKind.Explicit)]
		internal struct Win32Error
		{
			// Fields
			[FieldOffset(0)]
			private readonly int _value;

			public static readonly Win32Error ERROR_ACCESS_DENIED;
			public static readonly Win32Error ERROR_BAD_DEVICE;
			public static readonly Win32Error ERROR_CANCELLED;
			public static readonly Win32Error ERROR_FILE_NOT_FOUND;
			public static readonly Win32Error ERROR_INSUFFICIENT_BUFFER;
			public static readonly Win32Error ERROR_INVALID_DATATYPE;
			public static readonly Win32Error ERROR_INVALID_FUNCTION;
			public static readonly Win32Error ERROR_INVALID_HANDLE;
			public static readonly Win32Error ERROR_INVALID_PARAMETER;
			public static readonly Win32Error ERROR_INVALID_WINDOW_HANDLE;
			public static readonly Win32Error ERROR_KEY_DELETED;
			public static readonly Win32Error ERROR_NESTING_NOT_ALLOWED;
			public static readonly Win32Error ERROR_NO_MATCH;
			public static readonly Win32Error ERROR_NO_MORE_FILES;
			public static readonly Win32Error ERROR_OUTOFMEMORY;
			public static readonly Win32Error ERROR_PATH_NOT_FOUND;
			public static readonly Win32Error ERROR_SHARING_VIOLATION;
			public static readonly Win32Error ERROR_SUCCESS;
			public static readonly Win32Error ERROR_TIMEOUT;
			public static readonly Win32Error ERROR_TOO_MANY_OPEN_FILES;

			// Methods
			static Win32Error()
			{
				ERROR_SUCCESS = new Win32Error(0);
				ERROR_INVALID_FUNCTION = new Win32Error(1);
				ERROR_FILE_NOT_FOUND = new Win32Error(2);
				ERROR_PATH_NOT_FOUND = new Win32Error(3);
				ERROR_TOO_MANY_OPEN_FILES = new Win32Error(4);
				ERROR_ACCESS_DENIED = new Win32Error(5);
				ERROR_INVALID_HANDLE = new Win32Error(6);
				ERROR_OUTOFMEMORY = new Win32Error(14);
				ERROR_NO_MORE_FILES = new Win32Error(0x12);
				ERROR_SHARING_VIOLATION = new Win32Error(0x20);
				ERROR_INVALID_PARAMETER = new Win32Error(0x57);
				ERROR_INSUFFICIENT_BUFFER = new Win32Error(0x7a);
				ERROR_NESTING_NOT_ALLOWED = new Win32Error(0xd7);
				ERROR_KEY_DELETED = new Win32Error(0x3fa);
				ERROR_NO_MATCH = new Win32Error(0x491);
				ERROR_BAD_DEVICE = new Win32Error(0x4b0);
				ERROR_CANCELLED = new Win32Error(0x4c7);
				ERROR_INVALID_WINDOW_HANDLE = new Win32Error(0x578);
				ERROR_TIMEOUT = new Win32Error(0x5b4);
				ERROR_INVALID_DATATYPE = new Win32Error(0x70c);
			}

			public Win32Error(int i)
			{
				_value = i;
			}

			public override bool Equals(object obj)
			{
				try
				{
					return (((Win32Error)obj)._value == _value);
				}
				catch (InvalidCastException)
				{
					return false;
				}
			}

			public override int GetHashCode() => _value.GetHashCode();

			[SecurityCritical]
			public static Win32Error GetLastError() => new Win32Error(Marshal.GetLastWin32Error());

			public static bool operator ==(Win32Error errLeft, Win32Error errRight) => (errLeft._value == errRight._value);

			public static explicit operator HRESULT(Win32Error error)
			{
				if (error._value <= 0)
				{
					return new HRESULT((uint)error._value);
				}
				return HRESULT.Make(true, Facility.Win32, error._value & 0xffff);
			}

			public static bool operator !=(Win32Error errLeft, Win32Error errRight) => !(errLeft == errRight);

			public HRESULT ToHRESULT() => (HRESULT)this;
		}

		[ComImport, Guid("77f10cf0-3db5-4966-b520-b7c54fd35ed6"), ClassInterface(ClassInterfaceType.None)]
		public class CDestinationList { }

		[ComImport, Guid("2d3468c1-36a7-43b6-ac24-d3f02fd9607a"), ClassInterface(ClassInterfaceType.None)]
		public class CEnumerableObjectCollection { }

		[ComImport, Guid("00021401-0000-0000-C000-000000000046"), ClassInterface(ClassInterfaceType.None)]
		public class CShellLinkW { }

		[ComImport, Guid("56FDF344-FD6D-11d0-958A-006097C9A090"), ClassInterface(ClassInterfaceType.None)]
		public class CTaskbarList { }

		/// <remarks>
		/// Methods in this class will only work on Vista and above.
		/// </remarks>
		internal static class ShellUtil
		{
			/// <securitynote>
			///     Critical: Resolves an opaque Guid into a path on the user's machine.  Calls critical SHGetFolderPathEx
			/// </securitynote>
			[SecurityCritical]
			public static string GetPathForKnownFolder(Guid knownFolder)
			{
				if (knownFolder == default(Guid))
					return null;

				var pathBuilder = new StringBuilder(260);
				HRESULT hr = SHGetFolderPathEx(ref knownFolder, 0, IntPtr.Zero, pathBuilder, (uint)pathBuilder.Capacity);
				return hr.Succeeded ? pathBuilder.ToString() : null;
			}

			/// <securitynote>
			///     Critical: Resolves an opaque interface into a path on the user's machine.
			/// </securitynote>
			[SecurityCritical]
			public static string GetPathFromShellItem(IShellItem item) => item.GetDisplayName(SIGDN.DESKTOPABSOLUTEPARSING);

			/// <securitynote>
			///     Critical: Calls SHCreateItemFromParsingName
			/// </securitynote>
			[SecurityCritical]
			public static IShellItem2 GetShellItemForPath(string path)
			{
				if (string.IsNullOrEmpty(path))
					return null;

				Guid iidShellItem2 = new Guid("7e9fb0d3-919f-4307-ab2e-9b1860310c93");
				object unk;
				HRESULT hr = SHCreateItemFromParsingName(path, null, ref iidShellItem2, out unk);
				if (hr == (HRESULT)Win32Error.ERROR_FILE_NOT_FOUND || hr == (HRESULT)Win32Error.ERROR_PATH_NOT_FOUND)
				{
					hr = HRESULT.S_OK;
					unk = null;
				}
				hr.ThrowIfFailed();

				return (IShellItem2)unk;
			}
		}

		[StructLayout(LayoutKind.Sequential), SecurityCritical]
		public class REFPROPERTYKEY
		{
			public Guid fmtid;
			public int pid;

			public REFPROPERTYKEY(Guid id)
			{
				fmtid = id;
				pid = 2;
			}
		}

		[StructLayout(LayoutKind.Explicit), SecurityCritical]
		internal class PROPVARIANT : IDisposable
		{
			// Fields
			[FieldOffset(8)]
			private short boolVal;

			[FieldOffset(8)]
			private FILETIME ftVal;

			[FieldOffset(8)]
			private byte byteVal;

			[FieldOffset(8)]
			private double doubleVal;

			[FieldOffset(8)]
			private float floatVal;

			[FieldOffset(8)]
			private decimal decimalVal;

			[FieldOffset(8)]
			private long longVal;

			[FieldOffset(8)]
			private IntPtr pointerVal;

			[FieldOffset(8)]
			private int intVal;

			[FieldOffset(8)]
			private short shortVal;

			[FieldOffset(0)]
			private ushort vt;

			public PROPVARIANT() { }

			public PROPVARIANT(object value)
			{
				Value = value;
			}

			[SecurityCritical, SecurityTreatAsSafe]
			public void Clear()
			{
				NativeMethods.PropVariantClear(this);
			}

			[SecurityCritical, SecurityTreatAsSafe]
			public void Dispose()
			{
				Dispose(true);
				GC.SuppressFinalize(this);
			}

			[SecurityCritical, SecurityTreatAsSafe]
			private void Dispose(bool disposing)
			{
				Clear();
			}

			[SecurityCritical, SecurityTreatAsSafe]
			~PROPVARIANT()
			{
				Dispose(false);
			}

			[SecurityCritical, SecurityTreatAsSafe]
			public object Value
			{
				get
				{
					switch ((VarEnum)vt)
					{
						case VarEnum.VT_EMPTY:
						case VarEnum.VT_NULL:
							return DBNull.Value;
						case VarEnum.VT_I2:
							return shortVal;
						case VarEnum.VT_INT:
						case VarEnum.VT_I4:
						case VarEnum.VT_ERROR:
							return intVal;
						case VarEnum.VT_BSTR:
							return Marshal.PtrToStringBSTR(pointerVal);
						case VarEnum.VT_DISPATCH:
						case VarEnum.VT_UNKNOWN:
							return pointerVal == IntPtr.Zero ? null : Marshal.GetObjectForIUnknown(pointerVal);
						case VarEnum.VT_BOOL:
							return boolVal;
						case VarEnum.VT_I1:
							return (char)byteVal;
						case VarEnum.VT_UI1:
							return byteVal;
						case VarEnum.VT_UI2:
							return (ushort)shortVal;
						case VarEnum.VT_UINT:
						case VarEnum.VT_UI4:
							return (uint)intVal;
						case VarEnum.VT_I8:
							return longVal;
						case VarEnum.VT_UI8:
							return (ulong)longVal;
						case VarEnum.VT_VOID:
							return pointerVal;
						case VarEnum.VT_HRESULT:
							return pointerVal;
						case VarEnum.VT_PTR:
							return pointerVal;
						case VarEnum.VT_USERDEFINED:
							return pointerVal;
						case VarEnum.VT_LPSTR:
							return Marshal.PtrToStringAnsi(pointerVal);
						case VarEnum.VT_LPWSTR:
							return Marshal.PtrToStringUni(pointerVal);
						case VarEnum.VT_R8:
							return doubleVal;
						case VarEnum.VT_DATE:
							return DateTime.FromOADate(doubleVal);
						case VarEnum.VT_CY:
							return decimal.FromOACurrency(longVal);
						case VarEnum.VT_R4:
							return floatVal;
						case VarEnum.VT_DECIMAL:
							return decimalVal;
						case VarEnum.VT_FILETIME:
							return ftVal;
						/*case VarEnum.VT_VARIANT:
						case VarEnum.VT_CARRAY:
						case VarEnum.VT_RECORD:
						case VarEnum.VT_BLOB:
						case VarEnum.VT_SAFEARRAY:
						case VarEnum.VT_STREAM:
						case VarEnum.VT_STORAGE:
						case VarEnum.VT_STREAMED_OBJECT:
						case VarEnum.VT_STORED_OBJECT:
						case VarEnum.VT_BLOB_OBJECT:
						case VarEnum.VT_CF:
						case VarEnum.VT_CLSID:
						case VarEnum.VT_VECTOR:
						case VarEnum.VT_ARRAY:
						case VarEnum.VT_BYREF:*/
						default:
							break;
					}
					return null;
				}
				set
				{
					Clear();
					if (value == null || DBNull.Value.Equals(value))
					{
						vt = 1;
					}
					else if (value is bool)
					{
						vt = 11;
						boolVal = ((bool)value) ? ((short)(-1)) : ((short)0);
					}
					else if (value is string)
					{
						vt = 0x1f;
						pointerVal = Marshal.StringToCoTaskMemUni(value.ToString());
					}
					else if (value is byte)
					{
						vt = 17;
						byteVal = (byte)value;
					}
					else if (value is char)
					{
						vt = 16;
						byteVal = (byte)value;
					}
					else if (value is double)
					{
						vt = 5;
						doubleVal = (double)value;
					}
					else if (value is float)
					{
						vt = 4;
						floatVal = (float)value;
					}
					else if (value is decimal)
					{
						vt = 14;
						decimalVal = (decimal)value;
					}
					else if (value is DateTime)
					{
						vt = 7;
						doubleVal = ((DateTime)value).ToOADate();
					}
					else if (value is CurrencyWrapper)
					{
						vt = 6;
						decimalVal = ((CurrencyWrapper)value).WrappedObject;
					}
					else if (value is ulong)
					{
						vt = 0x15;
						longVal = Convert.ToInt64(value);
					}
					else if (value is long)
					{
						vt = 20;
						longVal = (long)value;
					}
					else if (value is IntPtr)
					{
						vt = 26;
						pointerVal = (IntPtr)value;
					}
					else if (value is int)
					{
						vt = 3;
						intVal = (int)value;
					}
					else if (value is uint)
					{
						vt = 0x13;
						intVal = Convert.ToInt32(value);
					}
					else if (value is short)
					{
						vt = 2;
						shortVal = (short)value;
					}
					else if (value is ushort)
					{
						vt = 2;
						shortVal = Convert.ToInt16(value);
					}
					else if (value is FILETIME)
					{
						vt = 64;
						ftVal = (FILETIME)value;
					}
					else if (Marshal.IsComObject(value))
					{
						var id = Marshal.GetIDispatchForObject(value);
						if (id != null)
						{
							vt = 9;
							pointerVal = id;
						}
						else
						{
							vt = 13;
							pointerVal = Marshal.GetIUnknownForObject(value);
						}
					}
				}
			}

			// Properties
			public VarEnum VarType
			{
				[SecurityCritical, SecurityTreatAsSafe]
				get
				{
					return (VarEnum)vt;
				}
			}

			// Nested Types
			private static class NativeMethods
			{
				// Methods
				[SecurityCritical, SuppressUnmanagedCodeSecurity, DllImport("ole32.dll")]
				internal static extern int PropVariantClear(PROPVARIANT pvar);
			}
		}
	}
}